import React, { Component } from 'react';
import styles from './index.less';
import { Button, Message, Popover, Upload } from 'antd';
import copy from 'copy-to-clipboard';
import { connect } from 'dva';
import { CopyOutlined, DownloadOutlined, ExportOutlined, FileZipOutlined, UploadOutlined } from '@ant-design/icons';
import DTree from '@/components/DTree';
import JSZip from 'jszip';
import CommonEditor from '@/pages/components/CommonEditor';
import GenerateModal from '@/pages/components/GenerateModal';

@connect(({ codeGenerate }) => ({
  codeGenerate,
}))
class CodeGeneratePage extends Component {

  constructor (props) {
    super(props);
    this.state = {
      current: 1,
      pageSize: 10,
      pages: 1,
      historyList: [],
      input: '',
      targetFiles: [{
        key: 0,
        fileType: 'java',
        fileName: '输出文件',
      }],
      targetContent: '',
      fileList: [],
      fileInfoList: [],
      uploading: false,
      inputType: 'sql',
      targetType: 'java',
      generateVisible: false,
      generateVueVisible: false,
      settingVisible: false,
      fieldOptions: [],
      fields: [],
      exportVisible: false,
      fileTree: null,
      selectKey: '',
      selectedFields: {},
      methods: {},
      generateLoading: false,
      generateVueLoading: false,
    };
  }

  inputChange = value => {
    this.setState({
      input: value,
      fieldOptions: [],
    });
  };

  targetChange = (selectKey, value) => {
    const { targetFiles = [] } = this.state;
    for (let targetFile of targetFiles) {
      const index = targetFile.fileName.lastIndexOf('/');
      const targetKey = targetFile.fileName.substring(index + 1);
      if (selectKey === targetKey) {
        targetFile.content = value;
      }
    }
    this.setState({
      targetContent: value,
      targetFiles,
    });
  };

  compressSource = () => {
    let { input } = this.state;
    const result = input.replace(new RegExp(/\s+/g), ' ');
    this.setState({
      input: result,
    });
  };

  copyCode = key => {
    this.copyValue(this.state[key]);
  };

  copyValue = value => {
    if (value) {
      copy(value);
      Message.success('已复制');
    }
  };

  beforeUpload = file => {
    const isLt2M = file.size / 1024 / 1024 < 5;
    if (!isLt2M) {
      Message.error('请选择小于5MB的文件!');
      return false;
    }

    const index = file.name.lastIndexOf('.');
    if (index < 0) {
      Message.error('未知的文件类型!');
      return false;
    }
  };

  upload = info => {
    let formData = new FormData();
    formData.append('file', info.file);
    this.props.dispatch({
      type: 'codeGenerate/importFile',
      payload: formData,
      callback: response => {
        if (response) {
          this.setState({
            input: response.data,
          });
          Message.success('导入成功！');
        }
      },
    });
  };

  downloadValue = selectKey => {
    const { targetFiles = [] } = this.state;
    let target = {};
    for (let targetFile of targetFiles) {
      const targetKey = targetFile.fileName;
      if (targetKey.endsWith(selectKey)) {
        target = targetFile;
        break;
      }
    }
    if (!target.content) {
      Message.warn('暂无可导出内容！');
      return;
    }
    this.downloadFile(selectKey, target.content);
  };

  downloadFile = (fileName, content) => {
    const fileContent = `data:,${content}`;
    const file = new Blob([fileContent], { type: 'text/plain' });
    const link = document.createElement('a');
    link.href = URL.createObjectURL(file);
    link.download = fileName;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(link.href);
  };

  generateOpen = () => {
    this.props.dispatch({
      type: 'codeGenerate/allTemplates',
      payload: {
        data: {},
      },
      callback: response => {
        if (response && response.code === 200) {
          this.setState({
            templates: response.data,
            generateVisible: true,
          });
        }
      },
    });
  };

  generateClose = () => {
    this.setState({
      generateVisible: false,
    });
  };

  generateSubmit = data => {
    const { input } = this.state;
    this.setState({
      generateLoading: true,
    });
    data['input'] = input;
    this.props.dispatch({
      type: 'codeGenerate/generateCode',
      payload: {
        data,
      },
      callback: response => {
        if (response && response.code === 200) {
          const split = response.data.results.length > 0 ? response.data.results[0].fileName.split('/') : [];
          this.setState({
            targetFiles: response.data.results,
            fileTree: response.data.fileTree,
            selectKey: response.data.results.length > 0 ? split[split.length - 1] : '',
            targetContent: response.data.results.length > 0 ? response.data.results[0].content : '',
            generateVisible: false,
            generateVueVisible: false,
            exportVisible: true,
            targetType: 'spring',
          });
        }
      },
    }).then(res => {
      this.setState({
        generateLoading: false,
      });
    });
  };

  execute = () => {
    const { input } = this.state;
    if (input === undefined || input.trim().length === 0) {
      Message.warn('请先输入文本内容！');
      return;
    }
    this.generateOpen();
  };

  exportCode = () => {
    const { targetFiles } = this.state;
    const zip = new JSZip();
    targetFiles.forEach(file => {
      zip.file(file.fileName, file.content);
    });
    zip.generateAsync({ type: 'blob' }).then(function(blob) {
      const a = document.createElement('a');
      const url = window.URL.createObjectURL(blob);
      a.href = url;
      a.download = 'export.zip';
      a.click();
      window.URL.revokeObjectURL(url);
    });
  };

  onSelect = key => {
    const { targetFiles = [] } = this.state;
    let targetContent = '';
    for (let targetFile of targetFiles) {
      if (targetFile.fileName.indexOf('/') >= 0) {
        const pathArr = targetFile.fileName.split('/');
        const fileKey = pathArr[pathArr.length - 1];
        if (fileKey === key) {
          targetContent = targetFile.content;
          break;
        }
      } else {
        if (targetFile.fileName === key) {
          targetContent = targetFile.content;
          break;
        }
      }
    }

    this.setState({
      selectKey: key,
      targetContent,
    });
  };

  render () {
    const {
      input,
      targetFiles = [],
      selectKey,
      targetContent,
      fileTree,
      templates,
      generateVisible,
    } = this.state;
    const childrenContent = {};
    targetFiles.forEach((item, index) => {
      const fileNameArr = item.fileName.split('/');
      //内容区域
      childrenContent[fileNameArr[fileNameArr.length - 1]] = {
        fileType: item.fileType,
        content: item.content,
      };
    });

    const sourceToolbar = <div className={styles['toolbar']}>
      <div>
        <Button
          type={'link'}
          style={{ color: '#fff', padding: '0px' }}
          onClick={this.compressSource}
          icon={<FileZipOutlined />}
        >
          文本压缩
        </Button>
      </div>
      <div style={{ display: 'flex' }}>
        <Upload
          {...this.state}
          beforeUpload={this.beforeUpload}
          customRequest={this.upload}
        >
          <Button
            type={'link'}
            style={{ color: '#fff', padding: '0px', marginLeft: '20px' }}
            icon={<UploadOutlined />}>
            导入建表SQL
          </Button>
        </Upload>
        <Button
          type={'link'}
          style={{ color: '#fff' }}
          onClick={() => this.copyCode('input')}
          icon={<CopyOutlined />}
        >
          复制
        </Button>
      </div>
    </div>;

    const targetToolBar = <div className={styles['toolbar']}>
      <div></div>
      <div style={{ display: 'flex' }}>
        <Button
          type={'link'}
          style={{ color: '#fff', padding: '0px', marginLeft: '20px' }}
          onClick={() => this.downloadValue(selectKey)}
          icon={<DownloadOutlined />}
        >
          导出当前文件
        </Button>
        <Button
          disabled={targetFiles.length < 2}
          type={'link'}
          style={{ color: '#fff', padding: '0px', marginLeft: '20px' }}
          onClick={this.exportCode}
          icon={<ExportOutlined />}
        >
          下载压缩包
        </Button>
        <Button
          type={'link'}
          style={{ color: '#fff', padding: '0px', marginLeft: '20px' }}
          onClick={() => this.copyValue(targetContent)}
          icon={<CopyOutlined />}
        >
          复制
        </Button>
      </div>
    </div>;

    return <div style={{ width: '100%', minWidth: '1000px', padding: '0 40px' }}>
      <div className={styles['slogan']}>
        <div style={{ textAlign: 'center' }}>
          <h1 className={styles['slogan-content']}>
            最好用的代码生成器
          </h1>
          <div style={{ fontSize: '16px', marginTop: '20px' }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
              <div>
                —— 极致灵活的配置选项
              </div>
              <div style={{ marginLeft: '20px' }}>
                —— 强大的模板功能
              </div>
            </div>
          </div>
        </div>
        <img src={'/svgs/code.svg'} style={{ width: '200px' }} />
      </div>

      <div style={{ display: 'flex', alignItems: 'flex-end' }}>
        <div style={{
          width: '100%',
          marginBottom: '20px',
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'flex-end',
        }}>
          <Button
            type={'danger'}
            style={{ width: '200px' }}
            onClick={() => this.execute('spring')}
            size={'large'}
          >
            立即生成
          </Button>
        </div>
      </div>

      <div className={styles['main']}>
        <div className={styles['editor-left']}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '5px' }}>
            <div style={{ display: 'flex', alignItems: 'center', fontSize: '16px', fontWeight: 600 }}>
              <div style={{ width: '4px', height: '20px', background: '#ff9200' }}></div>
              <img src={'/svgs/lunch-break-9.svg'} style={{ width: '50px' }} />
              <div>
                建表SQL语句
              </div>
            </div>
          </div>
          {sourceToolbar}
          <div className={styles['content']}>
            <CommonEditor
              mode={'sql'}
              theme={'solarized_dark'}
              content={input}
              onChange={this.inputChange}
            />
          </div>
        </div>
        <div className={styles['editor-right']}>
          <div
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              marginBottom: '5px',
              alignItems: 'flex-end',
            }}>
            <div
              style={{
                display: 'flex',
                alignItems: 'center',
                fontSize: '16px',
                fontWeight: 600,
              }}>
              <div style={{ width: '4px', height: '20px', background: '#ff9200' }}></div>
              <img src={'/svgs/java.svg'} style={{ width: '50px' }} />
              <div>生成结果</div>
              <Popover content={<div>
                <p><strong>1. 非标准的SQL语法：</strong>检查您的SQL中是否存在错误</p>
                <p><strong>2. 不匹配的解析器：</strong>选择与您的SQL语句相匹配的解析器</p>
              </div>}>
                <a style={{ fontSize: '14px', fontWeight: 500, marginLeft: '20px', color: '#909399' }}>可能生成失败的情况
                  <img src={'/icon/tips.svg'} style={{ width: '16px', margin: '0 0 3px 2px' }} />
                </a>
              </Popover>
            </div>
          </div>
          {targetToolBar}
          <div className={styles['content']}>
            <div>
              <div style={{ width: '100%', height: '800px', display: 'flex' }}>
                <div style={{ width: '400px' }}>
                  <DTree
                    width={300}
                    height={800}
                    onSelect={this.onSelect}
                    selectKey={selectKey}
                    datasource={fileTree}
                  />
                </div>
                <div style={{ width: '100%' }}>
                  <CommonEditor
                    mode={'java'}
                    theme={'solarized_dark'}
                    content={targetContent}
                    onChange={value => this.targetChange(selectKey, value)}
                  />
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
      {
        generateVisible &&
        <GenerateModal
          visible={generateVisible}
          submit={this.generateSubmit}
          cancel={this.generateClose}
          setting={this.state.setting}
          templates={templates}
          loading={this.state.generateLoading}
        />
      }
    </div>;
  }
}

export default CodeGeneratePage;
